package liming.tool.maven.tool;

import liming.tool.data.DataObject;
import liming.tool.file.FileRW;
import org.json.JSONObject;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import javax.xml.parsers.*;
import java.io.*;
import java.util.*;

public class XmlParser {
    public static JSONObject parseXmlJson(File xmlFile) throws Exception {
        return new JSONObject(parseXml(xmlFile));
    }
    public static Map<String, Object> parseXml(File xmlFile) throws Exception {
        String xmlContent = FileRW.readTextFile(xmlFile).getContent();
        return parseXmlString(xmlContent);
    }

    public static Map<String, Object> parseXmlString(String xmlString) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new InputSource(new StringReader(xmlString)));

        Map<String, Object> result = new HashMap<>();
        Node root = doc.getDocumentElement();
        result.put(root.getNodeName(),parseNode(root));
        return result;
    }

    private static Object parseNode(Node node) {
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            Element element = (Element) node;
            Map<String, Object> nodeMap = new LinkedHashMap<>();

            // 处理属性
            NamedNodeMap attributes = element.getAttributes();
            if (attributes.getLength() > 0) {
                Map<String, String> attrs = new LinkedHashMap<>();
                for (int i = 0; i < attributes.getLength(); i++) {
                    Node attr = attributes.item(i);
                    attrs.put(attr.getNodeName(), attr.getNodeValue());
                }
                nodeMap.put("@attributes", attrs);
            }

            // 处理子节点和文本内容
            NodeList children = element.getChildNodes();
            Map<String, Object> childrenMap = new LinkedHashMap<>();
            StringBuilder textContent = new StringBuilder();
            boolean hasComplexChildren = false;

            for (int i = 0; i < children.getLength(); i++) {
                Node child = children.item(i);
                if (child.getNodeType() == Node.ELEMENT_NODE) {
                    hasComplexChildren = true;
                    Object childData = parseNode(child);
                    mergeChild(childrenMap, child.getNodeName(), childData);
                } else if (child.getNodeType() == Node.TEXT_NODE) {
                    String text = child.getTextContent().trim();
                    if (!text.isEmpty()) {
                        textContent.append(text).append(" ");
                    }
                }
            }

            // 判断内容类型
            String textValue = textContent.toString().trim();
            if (textValue.length() > 0) {
                if (hasComplexChildren || !nodeMap.isEmpty()) {
                    nodeMap.put("#text", textValue);
                } else {
                    // 如果是纯文本节点，直接返回文本值
                    return textValue;
                }
            }

            if (!childrenMap.isEmpty()) {
                nodeMap.putAll(childrenMap);
            }

            // 如果节点没有内容，返回空Map
            return nodeMap.isEmpty() ? null : nodeMap;
        }
        return null;
    }

    private static void mergeChild(Map<String, Object> parent, String key, Object value) {
        if (parent.containsKey(key)) {
            Object existing = parent.get(key);
            if (existing instanceof List) {
                ((List<Object>) existing).add(value);
            } else {
                List<Object> list = new ArrayList<>();
                list.add(existing);
                list.add(value);
                parent.put(key, list);
            }
        } else {
            parent.put(key, value);
        }
    }

    public static void generateXml(Map<String, Object> data, File outputFile) throws IOException {
        String xmlContent = buildXml(data);
        FileRW.writeTextFile(outputFile, xmlContent, false);
    }

    private static String buildXml(Map<String, Object> data) {
        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
        for (Map.Entry<String, Object> entry : data.entrySet()) {
            buildNode(entry.getKey(), entry.getValue(), sb, 0);
        }
        return sb.toString();
    }

    @SuppressWarnings("unchecked")
    private static void buildNode(String name, Object value, StringBuilder sb, int indent) {
        String indentation = repeat("  ",indent);

        if (value instanceof Map) {
            Map<String, Object> nodeMap = (Map<String, Object>) value;
            sb.append(indentation).append("<").append(name);

            // 处理属性
            Map<String, String> attrs = (Map<String, String>) nodeMap.get("@attributes");
            if (attrs != null) {
                for (Map.Entry<String, String> attr : attrs.entrySet()) {
                    sb.append(" ")
                            .append(attr.getKey())
                            .append("=\"")
                            .append(escapeXml(attr.getValue()))
                            .append("\"");
                }
            }

            // 处理子节点和文本内容
            boolean hasChildren = nodeMap.entrySet().stream()
                    .anyMatch(e -> !e.getKey().equals("@attributes") && !e.getKey().equals("#text"));

            String text = (String) nodeMap.get("#text");
            if (!hasChildren && text == null) {
                sb.append("/>\n");
                return;
            }

            sb.append(">");

            if (text != null) {
                sb.append(escapeXml(text));
            }

            if (hasChildren) {
                sb.append("\n");
                for (Map.Entry<String, Object> entry : nodeMap.entrySet()) {
                    String key = entry.getKey();
                    if (key.equals("@attributes") || key.equals("#text")) continue;

                    Object childValue = entry.getValue();
                    if (childValue instanceof List) {
                        for (Object item : (List<?>) childValue) {
                            buildNode(key, item, sb, indent + 1);
                        }
                    } else {
                        buildNode(key, childValue, sb, indent + 1);
                    }
                }
                sb.append(indentation);
            }

            sb.append("</").append(name).append(">\n");
        } else if (value instanceof List) {
            for (Object item : (List<?>) value) {
                buildNode(name, item, sb, indent);
            }
        } else {
            sb.append(indentation)
                    .append("<").append(name).append(">")
                    .append(escapeXml(value.toString()))
                    .append("</").append(name).append(">\n");
        }
    }

    private static String escapeXml(String input) {
        return input.replace("&", "&amp;")
                .replace("<", "&lt;")
                .replace(">", "&gt;")
                .replace("\"", "&quot;")
                .replace("'", "&apos;");
    }

    static String repeat(String str,int index){
        StringBuilder sb = new StringBuilder("");
        for (int i = 0; i < index; i++)
            sb.append(str);
        return sb.toString();
    }
}